package com.atguigu.tingshu.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.client.TrackInfoFeignClient;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.order.OrderDetail;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.user.VipServiceConfig;
import com.atguigu.tingshu.order.helper.SignHelper;
import com.atguigu.tingshu.order.mapper.OrderInfoMapper;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.user.client.VipServiceConfigFeignClient;
import com.atguigu.tingshu.vo.order.OrderDerateVo;
import com.atguigu.tingshu.vo.order.OrderDetailVo;
import com.atguigu.tingshu.vo.order.OrderInfoVo;
import com.atguigu.tingshu.vo.order.TradeVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private UserInfoFeignClient userInfoFeignClient;

    @Resource
    private AlbumInfoFeignClient albumInfoFeignClient;

    @Resource
    private VipServiceConfigFeignClient vipServiceConfigFeignClient;
    @Qualifier("com.atguigu.tingshu.album.client.TrackInfoFeignClient")
    @Autowired
    private TrackInfoFeignClient trackInfoFeignClient;

    /**
     * 提交订单
     * @param orderInfoVo
     * @param userId
     * @return
     */
    @Override
    public String submitOrder(OrderInfoVo orderInfoVo, Long userId) {
        //1、校验签名
        Map map = JSON.parseObject(JSON.toJSONString(orderInfoVo), Map.class);
        SignHelper.checkSign(map);
        //  将支付方式变为“”;
        map.put("payWay", "");
        //2、防止重复提交订单
        //2。1获取页面流水号
        String tradeNo = orderInfoVo.getTradeNo();
        //2.2和缓存流水号比较
        String tradeKey="tradeNo:"+userId+":"+tradeNo;
        //lua脚本，删除tradeKey，0，表示没有tradeKey，就说明重复提交
        //  2.3 比较; 或 判断key是否存在;
        //        Boolean result = this.redisTemplate.opsForValue().setIfAbsent(tradeNoKey, tradeNo, 1, TimeUnit.DAYS);
        //        if (!result) {
        //            //  重复提交订单;
        //            throw new RuntimeException("重复提交订单");
        //        }
        //        String redisTradeNo = (String) this.redisTemplate.opsForValue().get(tradeNoKey);
        //        if (!tradeNo.equals(redisTradeNo)){
        //            //  重复提交订单;
        //            throw new RuntimeException("重复提交订单");
        //        }
        //        //  删除缓存的数据：
        //        this.redisTemplate.delete(tradeNoKey);
        //  定义lua脚本;
        String scriptText="if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" +
                "then\n" +
                "    return redis.call(\"del\",KEYS[1])\n" +
                "else\n" +
                "    return 0\n" +
                "end";
        DefaultRedisScript<Long> script = new DefaultRedisScript<>();
        script.setResultType(Long.class);
        script.setScriptText(scriptText);
        Long result = (Long) redisTemplate.execute(script, Arrays.asList(), tradeNo);
        if(0==result){
            //删除失败，页面值域缓存值不一致，重复提交了
            throw new RuntimeException("重复提交订单");
        }
        //3.判断支付方式
        if (!SystemConstant.ORDER_PAY_ACCOUNT.equals(orderInfoVo.getPayWay())) {
            //在线支付
        }else{
            //余额支付
        }
        //返回数据
        return "";
    }

    /**
     * 订单结算页
     * @param tradeVo
     * @param userId
     * @return
     */
    @Override
    public OrderInfoVo trade(TradeVo tradeVo, Long userId) {
        //初始金额
        BigDecimal originalAmount = new BigDecimal("0.00");
        //折扣金额
        BigDecimal derateAmount = new BigDecimal("0.00");
        //实付金额
        BigDecimal orderAmount = new BigDecimal("0.00");
        //订单明细列表
        List<OrderDetailVo> orderDetailVoList = new ArrayList<>();
        //订单折扣明细列表
        List<OrderDerateVo> orderDerateVoList = new ArrayList<>();

        //判断购买类型

        if (SystemConstant.ORDER_ITEM_TYPE_ALBUM.equals(tradeVo.getItemType())) {
            //如果时专辑
            //判断用户是否购买过专辑
            Result<Boolean> result=userInfoFeignClient.isPaidAlbum(tradeVo.getItemId());
            Assert.notNull(result,"调用判断用户是否购买过专辑失败");
            if (result.getData()) {
                throw new RuntimeException("用户购买过专辑");
            }
            //没买过
            //获取专辑信息
            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(tradeVo.getItemId());
            Assert.notNull(albumInfoResult,"远程调用获取专辑信息失败");
            AlbumInfo albumInfo = albumInfoResult.getData();
            Assert.notNull(albumInfo,"远程调用获取专辑信息失败");

            //设置原始金额
            originalAmount = albumInfo.getPrice();

            //获取用户信息
            Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfo(userId);
            Assert.notNull(userInfoVoResult,"远程调用获取用户信息失败");
            UserInfoVo userInfoVo = userInfoVoResult.getData();
            Assert.notNull(userInfoVo,"远程调用获取用户信息失败");

            if (0==userInfoVo.getIsVip()||(1==userInfoVo.getIsVip() && userInfoVo.getVipExpireTime().before(new Date()))){
                //普通用户
                if (albumInfo.getDiscount().compareTo(new BigDecimal("-1"))!=0) {
                    //获取折扣价格 打8.8折,100*(10-8.8)/10
                    derateAmount=originalAmount.multiply(new BigDecimal("10").subtract(albumInfo.getDiscount()).divide(new BigDecimal("10"),2, RoundingMode.UP));
                }
            }else{
                //vip用户
                if (albumInfo.getVipDiscount().compareTo(new BigDecimal("-1"))!=0) {
                    derateAmount=originalAmount.multiply(new BigDecimal("10").subtract(albumInfo.getVipDiscount()).divide(new BigDecimal("10"),2, RoundingMode.UP));
                }

            }
            //实付价格
            orderAmount=originalAmount.subtract(derateAmount);
            //生成订单明细
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(tradeVo.getItemId());
            orderDetailVo.setItemName(albumInfo.getAlbumTitle());
            orderDetailVo.setItemPrice(originalAmount);
            orderDetailVo.setItemUrl(albumInfo.getCoverUrl());
            orderDetailVoList.add(orderDetailVo);
            //生成折扣明细
            if (derateAmount.compareTo(new BigDecimal("0"))!=0) {
                OrderDerateVo orderDerateVo = new OrderDerateVo();
                orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_ALBUM_DISCOUNT);
                orderDerateVo.setDerateAmount(derateAmount);
                orderDerateVo.setRemarks("专辑折扣");
                orderDerateVoList.add(orderDerateVo);
            }
        }else if(SystemConstant.ORDER_ITEM_TYPE_TRACK.equals(tradeVo.getItemType())){
            //购买声音
            //1、购买声音数目不能小于0，o本集，>0其他
            if(tradeVo.getTrackCount()<0){
                throw new RuntimeException("购买声音数目不能小于0");
            }

            //2、根据声音ID，购买集数，获取订单结算页上购买的声音列表---feign track服务
            Result<List<TrackInfo>> trackInfoListResult =trackInfoFeignClient.findPaidTrackInfoList(tradeVo.getItemId(),tradeVo.getTrackCount());
            Assert.notNull(trackInfoListResult,"远程调用获取订单结算页上购买的声音列表失败");
            List<TrackInfo> trackInfoList = trackInfoListResult.getData();
            Assert.notNull(trackInfoList,"远程调用获取订单结算页上购买的声音列表失败");

            //获取专辑信息
            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(trackInfoList.get(0).getAlbumId());
            Assert.notNull(albumInfoResult,"远程调用获取专辑信息失败");
            AlbumInfo albumInfo = albumInfoResult.getData();
            Assert.notNull(albumInfo,"远程调用获取专辑信息失败");

            //3、计算原始价格，订单价格，另外声音不打折
            //原始金额=实际金额=单价(albumInfo.getPrice())*数量(trackCount);  0 本集，n 本集后的n集
            originalAmount= tradeVo.getTrackCount()==0?albumInfo.getPrice():albumInfo.getPrice().multiply(new BigDecimal(String.valueOf(tradeVo.getTrackCount())));
            orderAmount=originalAmount;
            //4、批量处理购买声音列表，获取订单明细 。List<TrackInfo>--->List<orderDetailVo>
            orderDetailVoList = trackInfoList.stream().map(trackInfo -> {
                OrderDetailVo orderDetailVo = new OrderDetailVo();
                orderDetailVo.setItemId(trackInfo.getId());
                orderDetailVo.setItemName(trackInfo.getTrackTitle());
                orderDetailVo.setItemPrice(albumInfo.getPrice());
                orderDetailVo.setItemUrl(trackInfo.getCoverUrl());
                return orderDetailVo;
            }).collect(Collectors.toList());

        }else{
            //购买vip

            //获取VIP信息
            //  获取vip_service_config对应数据;
            Result<VipServiceConfig> vipServiceConfigResult = vipServiceConfigFeignClient.getVipServiceConfig(tradeVo.getItemId());
            Assert.notNull(vipServiceConfigResult,"远程调用获取vip_service_config对应数据失败");
            VipServiceConfig vipServiceConfig = vipServiceConfigResult.getData();
            Assert.notNull(vipServiceConfig,"远程获取vip_service_config对应数据失败");
            //原始金额
            originalAmount=vipServiceConfig.getPrice();
            //折扣价格
            derateAmount=originalAmount.subtract(vipServiceConfig.getDiscountPrice() );

            //  实际金额
            orderAmount =vipServiceConfig.getDiscountPrice() ;
            //生成订单明细
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(tradeVo.getItemId());
            orderDetailVo.setItemName(vipServiceConfig.getName());
            orderDetailVo.setItemPrice(originalAmount);
            orderDetailVo.setItemUrl(vipServiceConfig.getImageUrl());
            orderDetailVoList.add(orderDetailVo);
            //生成折扣明细
            //  订单减免;
            if (derateAmount.compareTo(new BigDecimal("0")) != 0) {
                OrderDerateVo orderDerateVo = new OrderDerateVo();
                //  折扣金额大于0;
                orderDerateVo.setDerateAmount(derateAmount);
                orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT);
                orderDerateVo.setRemarks("vip折扣");
                orderDerateVoList.add(orderDerateVo);
            }
        }



        //整合返回结果

        //创建一个vo对象
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        //生成订单流水号
        String tradeNo = UUID.randomUUID().toString().replaceAll("-", "");
        String tradeKey="tradeNo:"+userId+":"+tradeNo;
        //防止重复提交订单
        redisTemplate.opsForValue().setIfAbsent(tradeKey,tradeNo,15, TimeUnit.MINUTES);
        //付费方式默认 空
        orderInfoVo.setPayWay("");
        orderInfoVo.setItemType(tradeVo.getItemType());
        orderInfoVo.setOriginalAmount(originalAmount);
        orderInfoVo.setDerateAmount(derateAmount);
        orderInfoVo.setOrderAmount(orderAmount);
        orderInfoVo.setOrderDetailVoList(orderDetailVoList);
        orderInfoVo.setOrderDerateVoList(orderDerateVoList);
        //时间戳：自定义
        long timestamp = SignHelper.getTimestamp();
        orderInfoVo.setTimestamp(timestamp);
        //签名：自定义，vo-》string->map
        Map map = JSON.parseObject(JSON.toJSONString(orderInfoVo), Map.class);
        //通过| 拼接实体类的属性值; 并追加一个盐(固定字符串),再采用md5 加密得到的字符串
        String sign = SignHelper.getSign(map);
        orderInfoVo.setSign(sign);
        //返回结果
        return orderInfoVo;
    }
}
